package org.rcgwt.client.ui.grid.renderer;

import org.rcgwt.client.ui.grid.internal.model.ICellModel;
import org.rcgwt.client.ui.grid.internal.model.IColumnModel;
import org.rcgwt.client.ui.grid.internal.model.IGridModel;
import org.rcgwt.client.ui.grid.internal.model.IRowModel;
import org.rcgwt.client.ui.grid.internal.model.IViewModel;
import org.rcgwt.client.ui.grid.theme.CssStyle;
import org.rcgwt.client.ui.grid.theme.IGridTheme;

import com.allen_sauer.gwt.log.client.Log;
import com.google.gwt.dom.client.Element;
import com.google.gwt.dom.client.NodeList;
import com.google.gwt.dom.client.TableCellElement;
import com.google.gwt.dom.client.TableRowElement;
import com.google.gwt.dom.client.TableSectionElement;

/**
 * Default Row Renderer Define Row Id
 * 
 * @author Olivier Oeuillot
 * 
 */
public class DefaultRowRenderer extends AbstractRenderer<IRowModel> implements
        IRowRenderer {

    /**
	 * 
	 */
    public Element render(IViewRenderContext viewRenderContext,
            Element parentElement, IRowModel rowModel, int renderedIndex) {

        assert parentElement instanceof TableSectionElement : "Invalid parent type ("
                + parentElement + ")";

        TableRowElement rowElement = parentElement.getOwnerDocument()
                .createTRElement();

        update(viewRenderContext, rowElement, rowModel, renderedIndex);

        return rowElement;
    }

    @Override
    public void update(IViewRenderContext viewRenderContext,
            Element rowElement, IRowModel rowModel, int renderedIndex) {
        super.update(viewRenderContext, rowElement, rowModel, renderedIndex);

        viewRenderContext.getViewModel().getViewModelElements().setRowElement(
                rowModel, rowElement, renderedIndex, true);
    }

    @Override
    protected CssStyle getCssStyle(IViewRenderContext viewRenderContext,
            IRowModel row) {
        IGridRenderContext gridRenderContext = viewRenderContext
                .getGridRenderContext();

        return gridRenderContext.getTheme().getRowStyleName(null, row);
    }

    @Override
    protected void updateContent(IViewRenderContext viewRenderContext,
            Element rowElement, IRowModel rowModel) {
        Log.debug("Update content of row " + rowModel.getModelIndex());

        IGridRenderContext gridRenderContext = viewRenderContext
                .getGridRenderContext();

        IViewModel viewModel = viewRenderContext.getViewModel();
        IGridModel gridModel = viewModel.getGridModel();

        IGridTheme theme = gridRenderContext.getTheme();

        viewModel.getViewModelElements()
                .clearCellElements(rowModel, rowElement);

        int cellElementsCount = 0;
        NodeList<TableCellElement> cellElements = null;

        if (rowElement.hasChildNodes()) {
            cellElements = TableRowElement.as(rowElement).getCells();
            cellElementsCount = cellElements.getLength();
        }

        int columnModelIndexes[] = gridRenderContext.getColumnModelIndexes();

        IColumnModel columnModels[] = gridModel.listColumnModels();

        int renderedColumnIndex = 0;
        for (; renderedColumnIndex < columnModelIndexes.length; renderedColumnIndex++) {
            int columnModelIndex = columnModelIndexes[renderedColumnIndex];

            IColumnModel columnModel = columnModels[columnModelIndex];

            ICellModel cell = rowModel.setupSharedCellModel(columnModel);

            if (renderedColumnIndex < cellElementsCount) {
                Element cellElement = cellElements.getItem(renderedColumnIndex);

                updateChild(viewRenderContext, theme, cellElement, cell,
                        renderedColumnIndex);
                continue;
            }

            Element cellElement = renderChild(viewRenderContext, theme,
                    rowElement, cell, renderedColumnIndex);

            rowElement.appendChild(cellElement);
        }

        for (; renderedColumnIndex < cellElementsCount; cellElementsCount--) {
            Element cellElement = cellElements.getItem(renderedColumnIndex);

            rowElement.removeChild(cellElement);
        }
    }

    protected void updateChild(IViewRenderContext viewRenderContext,
            IGridTheme theme, Element cellElement, ICellModel cell,
            int renderedIndex) {

        IRenderer<ICellModel> cellRenderer = theme.getCellRenderer(cell);

        cellRenderer
                .update(viewRenderContext, cellElement, cell, renderedIndex);

    }

    protected Element renderChild(IViewRenderContext viewRenderContext,
            IGridTheme theme, Element rowElement, ICellModel cell,
            int renderedIndex) {

        IRenderer<ICellModel> cellRenderer = theme.getCellRenderer(cell);

        Element cellElement = cellRenderer.render(viewRenderContext,
                rowElement, cell, renderedIndex);

        return cellElement;
    }

    @Override
    public Element getCellElement(Element rowElement, ICellModel cellModel,
            int renderedIndex) {
        TableRowElement tableRowElement = TableRowElement.as(rowElement);

        return tableRowElement.getCells().getItem(renderedIndex);
    }

    @Override
    protected void show(IViewRenderContext viewRenderContext,
            Element viewElement, IRowModel modelElement) {
        int elementTop = viewElement.getOffsetTop();
        int elementLeft = viewElement.getOffsetLeft();
        int elementWidth = viewElement.getOffsetWidth() + 2; // Marge
        int elementHeight = viewElement.getOffsetHeight() + 2; // Marge

        if (elementTop > 0) {
            elementTop--;
            elementHeight++;
        }
        if (elementLeft > 0) {
            elementLeft--;
            elementWidth++;
        }

        IViewModel viewModel = viewRenderContext.getViewModel();

        int viewLeft = viewModel.getScrollLeft();
        int viewTop = viewModel.getScrollTop();

        IViewRenderer viewRenderer = viewRenderContext.getGridRenderContext()
                .getTheme().getViewRenderer(viewModel);

        int viewSizes[] = viewRenderer.getSizes(viewRenderContext, viewElement,
                viewModel, null);

        int newViewLeft = viewLeft;
        if (newViewLeft >= elementLeft) {
            newViewLeft = elementLeft;

        } else if (newViewLeft + viewSizes[0] < elementLeft + elementWidth) {
            newViewLeft = elementLeft + elementWidth - viewSizes[0];
        }

        int newViewTop = viewTop;
        if (newViewTop >= elementTop) {
            newViewTop = elementTop;

        } else if (newViewTop + viewSizes[1] < elementTop + elementHeight) {
            newViewTop = elementTop + elementHeight - viewSizes[1];
        }

        if (false) {
            Log.debug("element=(" + elementLeft + "," + elementTop + " "
                    + elementWidth + "," + elementHeight + ") view=("
                    + viewLeft + "," + viewTop + " " + viewSizes[0] + ","
                    + viewSizes[1] + ") => " + newViewLeft + "," + newViewTop);
        }

        if (newViewLeft != viewLeft || newViewTop != viewTop) {
            viewRenderer.setScrollPositions(viewRenderContext, viewElement,
                    viewModel, newViewLeft, newViewTop);
        }
    }

}
